package mk.jug.academy.service;

import mk.jug.academy.exception.BusinessException;
import mk.jug.academy.model.Page;
import mk.jug.academy.model.Supporter;
import mk.jug.academy.model.SupporterStatus;
import mk.jug.academy.preconditions.ErrorCodes;
import mk.jug.academy.testing.bdd.IntegrationBehavior;
import mk.jug.academy.testing.factory.SupporterTestFactory;
import mk.jug.academy.testing.util.TestHelper;

import org.springframework.beans.factory.annotation.Autowired;

import com.googlecode.instinct.marker.annotate.Specification;
import com.googlecode.instinct.marker.annotate.Specification.SpecificationState;
import com.googlecode.instinct.marker.annotate.Subject;

/**
 * An integration test revolving around a {@link Supporter} lifecycle.
 *
 * @author Ice.Penov
 */
public class SupporterLifecycle extends IntegrationBehavior {
	
	@Autowired private SupporterService supporterService;	
	
	@Subject private Supporter supporter;
	@Subject private Supporter supporter1;
	@Subject private Supporter supporter2;
	@Subject private Supporter supporter3;
	
	@Override
	protected void beforeHook() {
		supporter = SupporterTestFactory.createSupporter();
		supporter1 = SupporterTestFactory.createSupporter();
		supporter2 = SupporterTestFactory.createSupporter();
		supporter3 = SupporterTestFactory.createSupporter();
		TestHelper.init(supporterService);		
	}
	
	/**
	 * User action:
	 * A {@link Supporter} with already registered email tries to sign up.
	 * 
	 * Expected behavior:
	 * 1. Throw an {@link BusinessException} with the appropriate error code.
	 */
	@Specification(state = SpecificationState.COMPLETE)
	public void failToSignUpSupporterWithExistingEmail() {
		supporterService.signUpSupporter(supporter);
		new ExceptionExpectation() {
			public void execute() {
				supporterService.signUpSupporter(supporter);
			}
		}.checkForErrorCode(BusinessException.class, ErrorCodes.ERROR_EMAIL_EXISTS);
	}
	
	/**
	 * User action:
	 * A {@link Supporter} signs up.
	 * 
	 * Expected behavior:
	 * 1. The {@link Supporter} should be listed as {@link SupporterStatus#SIGNED_UP}.
	 */
	@Specification(state = SpecificationState.COMPLETE)
	public void signUpSupporter() {
		supporterService.signUpSupporter(supporter);
		expect.that(supporterService.listSignedUp(1, 2).getItems()).containsItem(supporter);
		expect.that(supporterService.listSignedUp(1, 2).getItems()).isOfSize(1);
	}
	
	/**
	 * User action:
	 * A {@link Supporter} is being activated.
	 * 
	 * Expected behavior:
	 * 1. The {@link Supporter} should be listed as {@link SupporterStatus#ACTIVE}.
	 */
	@Specification(state = SpecificationState.COMPLETE)
	public void activateSupporter() {
		supporterService.signUpSupporter(supporter);
		supporterService.activateSupporter(supporter);
		expect.that(supporterService.listActive(1, 2).getItems()).containsItem(supporter);
		expect.that(supporterService.listActive(1, 2).getItems()).isOfSize(1);
	}
	
	/**
	 * User action:
	 * A {@link Supporter} is being deleted.
	 * 
	 * Expected behavior:
	 * 1. The {@link Supporter} should be listed as {@link SupporterStatus#DELETED}.
	 */
	@Specification(state = SpecificationState.COMPLETE)
	public void deleteSupporter() {
		TestHelper.prepareSupporter(supporter);
		supporterService.deleteSupporter(supporter);
		expect.that(supporterService.listDeleted(1, 2).getItems()).containsItem(supporter);
		expect.that(supporterService.listDeleted(1, 2).getItems()).isOfSize(1);
	}
	
	/**
	 * User action:
	 * Fetch the {@link Supporter}s in a paged manner.
	 * 
	 * Expected behavior:
	 * List the records as expected.
	 */
	@Specification(state = SpecificationState.COMPLETE)
	public void navigateSupportersUsingPaging() {
		supporter1.setRating(1);
		supporter2.setRating(2);
		supporter3.setRating(3);		
		TestHelper.prepareSupporter(supporter1);
		TestHelper.prepareSupporter(supporter2);
		TestHelper.prepareSupporter(supporter3);
		//open the pages.
		Page<Supporter> page1 = supporterService.listSignedUp(1, 2);
		Page<Supporter> page2 = supporterService.listSignedUp(2, 2);
		Page<Supporter> page3 = supporterService.listSignedUp(3, 2);
		//expectations.
		//size:
		expect.that(page1.getTotalCount()).isEqualTo(3);		
		expect.that(page2.getTotalCount()).isEqualTo(3);		
		expect.that(page3.getTotalCount()).isEqualTo(3);
		expect.that(page1.getItems()).isOfSize(2);
		expect.that(page2.getItems()).isOfSize(1);
		expect.that(page3.getItems()).isEmpty();
		//check contents of the pages:
		expect.that(page1.getItems()).containsItems(supporter3, supporter2);
		expect.that(page2.getItems()).containsItem(supporter1);
	}

}